一、為什麼需要搜尋功能?
想像一下,當資料庫只有兩三筆病患資料時,我們可以直接在清單中查看。
但如果資料庫裡有幾百筆,甚至幾千筆資料呢?
每次都從第一筆慢慢找,顯然不太方便。
因此,今天我們要為醫療資訊小系統加入一個實用功能:病患資料搜尋。
使用者可以輸入姓名,系統就會從 MySQL 找出符合條件的紀錄。
這篇會把前面學過的 HTML 表單、Servlet、JDBC 和 JSP 串接起來。
二、先認識 SQL 的 LIKE
如果要搜尋姓名包含特定文字的資料,可以使用 SQL 的 LIKE。
例如:
SELECT id, name, gender, birthday, phone
FROM patient
WHERE name LIKE '%小明%';
這裡的 % 是 SQL 的萬用字元,代表可以符合零個或多個字元。
因此:
實際搜尋結果會受到資料庫的字元排序規則等設定影響。
三、建立搜尋 Servlet
接下來,我們建立 PatientSearchServlet.java。
這個 Servlet 會接收使用者輸入的關鍵字,再利用 JDBC 查詢資料庫。
package servlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import model.Patient;
import util.DBConnection;
@WebServlet("/patient/search")
public class PatientSearchServlet extends HttpServlet {
@Override
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String keyword = request.getParameter("keyword");
if (keyword == null) {
keyword = "";
}
keyword = keyword.trim();
List patients = new ArrayList<>();
String sql = "SELECT id, name, gender, birthday, phone "
+ "FROM patient "
+ "WHERE name LIKE ? "
+ "ORDER BY id DESC";
try (
Connection conn = DBConnection.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)
) {
ps.setString(1, "%" + keyword + "%");
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
Patient patient = new Patient(
rs.getInt("id"),
rs.getString("name"),
rs.getString("gender"),
rs.getDate("birthday"),
rs.getString("phone")
);
patients.add(patient);
}
}
} catch (SQLException e) {
throw new ServletException("搜尋病患資料失敗", e);
}
request.setAttribute("keyword", keyword);
request.setAttribute("patients", patients);
request.getRequestDispatcher("/patient-search.jsp")
.forward(request, response);
}
}
這裡沿用了 Day 19 建立的 Patient.java,因此不需要重新設計病患資料類別。
如果你的套件名稱不是 model、servlet 或 util,請依照自己的專案結構調整。
四、看懂搜尋的核心程式
最重要的是這兩行:
String sql = "SELECT id, name, gender, birthday, phone "
+ "FROM patient WHERE name LIKE ?";
ps.setString(1, "%" + keyword + "%");
第一行定義 SQL 查詢條件,第二行將使用者輸入的關鍵字放進參數。
例如,使用者輸入:
小明
程式設定的參數就會是:
%小明%
這樣就能搜尋姓名中包含「小明」的資料。
請不要直接把使用者輸入的文字串接進 SQL 指令。使用 PreparedStatement 設定參數,可以避免把使用者輸入當成 SQL 語法執行。
五、建立搜尋頁面
現在我們要讓使用者能夠輸入搜尋條件。
建立 patient-search.jsp:
<%@ page contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ taglib prefix="c"
uri="jakarta.tags.core" %>
這個頁面包含搜尋表單和結果表格。
其中,<c:forEach> 負責逐筆顯示資料,<c:choose> 則會依照是否有搜尋結果,決定顯示表格還是提示訊息。
請確認專案已經加入相容版本的 JSTL/Jakarta Tags 依賴,才能使用這些標籤。
六、如何測試搜尋功能?
啟動 MySQL 和 Tomcat,然後開啟:
http://localhost:8080/你的專案名稱/patient/search
請把網址中的「你的專案名稱」替換成實際的專案 Context Path。
接著可以測試以下情況:
測試方式 預期結果
搜尋完整姓名 顯示符合的資料
搜尋姓名中的部分文字 顯示包含關鍵字的資料
搜尋不存在的姓名 顯示沒有符合條件的提示
不輸入關鍵字直接搜尋 顯示全部資料
最後一項會成立,是因為空字串加上萬用字元後,搜尋條件會變成 LIKE '%%'。在一般情況下,這會符合所有非 NULL 的姓名欄位。
七、搜尋功能還可以如何擴充?
目前我們只搜尋姓名,未來還可以依照系統需求增加:
如果要搜尋真實病患資訊,還必須確認使用者有適當權限,並避免在網址、日誌或公開畫面中暴露不必要的敏感資料。
另外,當資料量很大時,也應考慮查詢效能、索引設計與資料庫的字元排序規則。
今日小結
今天我們完成了基本的病患姓名搜尋功能。
這篇學到:
Day 22 完成!
到目前為止,我們的醫療資訊小系統已經具備新增、查詢、修改、刪除與搜尋等基本操作。接下來可以繼續加入表單驗證、登入與權限管理,讓系統的完整度更進一步。
參考資料:Jakarta Servlet 官方文件|Oracle Java Tutorials:Using Prepared Statements